package com.zhuangjie.shop.controller;


import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zhaungjie.base.conduit.R;
import com.zhuangjie.base.constant.ModuleSecurityNames;
import com.zhuangjie.base.enums.VerificationCodeScenes;
import com.zhuangjie.base.vo.PageVO;
import com.zhuangjie.mvc.annotation.ParamInject;
import com.zhuangjie.mvc.helper.GeoHelper.GeoCoordinates;
import com.zhuangjie.mvc.helper.GeoHelper.process.GeoConvert;
import com.zhuangjie.mvc.validator.annotate.PhoneNumber;
import com.zhuangjie.mvc.validator.annotate.ValidInteger;
import com.zhuangjie.security.annotations.NoAuthentication;
import com.zhuangjie.security.annotations.OnlySystemCall;
import com.zhuangjie.security.annotations.PublicAPI;
import com.zhuangjie.security.annotations.RequiresRoles;
import com.zhuangjie.shop.dto.FollowShopPageDTO;
import com.zhuangjie.shop.dto.SearchNearbyStoresPageDTO;
import com.zhuangjie.shop.dto.SettleInDTO;
import com.zhuangjie.shop.enums.BusinessTypeEnum;
import com.zhuangjie.shop.enums.ShopBusinessStatus;
import com.zhuangjie.shop.enums.ShopRole;
import com.zhuangjie.shop.feign.ThirdPartyFeignService;
import com.zhuangjie.shop.pojo.ShopBasicInfo;
import com.zhuangjie.shop.pojo.ShopBusinessConfig;
import com.zhuangjie.shop.service.ShopService;
import com.zhuangjie.shop.vo.*;
import com.zhuangjie.shop.vo.shop_display.NearbyShopVO;
import com.zhuangjie.shop.vo.predetermine.GeneratedPredetermineDayAndTimesInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * <p>
 * 商家/商店 前端控制器
 * </p>
 *
 * @author zhuangjie
 * @since 2023-09-24
 */
@RestController
@RequestMapping("/shop")
@Api("店铺")
public class ShopController {
    @Resource
    private ShopService shopService;

    @Resource
    private ThirdPartyFeignService thirdPartyFeignService;

    @GetMapping("/sendSettleInPhoneCode")
    @NoAuthentication
    @ApiOperation("发送店铺入驻手机验证码")
    public R sendSettleInPhoneCode(@PhoneNumber(hasAreaCode = true) @RequestParam("phone") String phone)  {
        return R.capture(()-> thirdPartyFeignService.sendCode(VerificationCodeScenes.SHOP_SETTLE_IN,phone));
    }

    @PostMapping("/settleIn")
    @NoAuthentication
    @ApiOperation("提交店铺入驻表单")
    public R settleIn(@Valid @RequestBody @GeoConvert SettleInDTO settleInDTO)  {
        return R.capture(()-> shopService.settleIn(settleInDTO));
    }

    @PostMapping("/approveResidencyApplication")
    @NoAuthentication
    @ApiOperation("测试接口：通过入驻申请")
    public R approveResidencyApplication(@RequestParam("shopId") Long shopId) {
        return R.capture(()->shopService.approveResidencyApplication(shopId));
    }
    @GetMapping("/status")
    @NoAuthentication
    @ApiOperation("获取店铺的状态")
    public R getShopStatus(@RequestParam(value = "shopId",required = false) Long shopId) throws Exception {
        Integer shopBusinessStatus = shopService.getShopBusinessStatus(shopId);
        return R.ok().data(shopBusinessStatus);
    }

    @PostMapping("/changeShopStatus")
    @ApiOperation("修饰店铺的状态")
    public R changeShopStatus(@ValidInteger({ShopBusinessStatus.OPEN,ShopBusinessStatus.CLOSE}) @RequestParam("businessStatus") Integer businessStatus) {
        return R.capture(()->shopService.changeShopStatus(businessStatus));
    }

    @GetMapping("/searchNearbyStores")
    @ApiOperation("获取附近店铺信息")
    @NoAuthentication
    public R searchNearbyStores(@ParamInject SearchNearbyStoresPageDTO searchNearbyStoresPageDTO) {
        Page<NearbyShopVO> nearbyShopPage = shopService.searchNearbyStores(searchNearbyStoresPageDTO);
        return R.ok().dataAsMap(map->{
            map.put("total",nearbyShopPage.getTotal());
            map.put("data",nearbyShopPage.getRecords());
        });
    }



    @GetMapping("/{shopId}")
    @ApiOperation("获取指定店铺的信息")
    @NoAuthentication
    public R getShopInfoById(@Min(value = 0,message = "店铺id不能为空") @PathVariable("shopId") Long shopId) throws ExecutionException, InterruptedException {
        ShopInfoVO shopInfo = shopService.getShopInfoById(shopId);
        return R.ok().data(shopInfo);
    }

    @GetMapping("/shop-predetermine-info")
    @ApiOperation("获取店铺预定信息-需要前端自行计算版")
    @NoAuthentication
    public R shopBusinessInfo(@NotNull(message = "店铺id不能为空") @RequestParam("shopId") Long shopId) throws ExecutionException, InterruptedException {
        return R.ok().data(shopService.getShopBusinessInfo(shopId));
    }

    /**
     * 商店营业时间段-内部使用接口 (这并不是开放的，需要用用户的身份来请求)
     *
     * @param shopId          店铺id
     * @param receivingMethod 接收方法
     * @param addressBookId   通讯簿id 如果是配送时必须
     * @return {@link R}
     * @throws Exception 例外
     */
    @GetMapping("/shop-predetermine/days-timeRanges/internal-use")
    @ApiOperation("获取店铺预定信息-内部模块使用")
    @PublicAPI(modules = {ModuleSecurityNames.USER})
    public R shopBusinessDaysTimeRangesForInternalUse(@NotNull(message = "店铺id不能为空") @RequestParam("shopId") Long shopId ,
                                   @Pattern(regexp = "["+ BusinessTypeEnum.ALL+"]", message = "交付方式值错误！") String receivingMethod,
                                   @RequestParam(required = false) Long addressBookId) throws Exception {
        PredetermineDayAndTimeRangesForInternalUse generatedPredetermineDayAndTimesInfo =  shopService.getShopBusinessDaysTimeRangesForInternalUse(shopId,receivingMethod,addressBookId);
        return R.ok().data(generatedPredetermineDayAndTimesInfo);
    }

    /**
     * 商店营业日时间 (这并不是开放的，需要用用户的身份来请求)
     *
     * @param shopId          店铺id
     * @param receivingMethod 接收方法
     * @param addressBookId   通讯簿id 如果是配送时必须
     * @return {@link R}
     * @throws Exception 例外
     */
    @GetMapping("/shop-predetermine-days-times")
    @ApiOperation("获取店铺预定信息-免前端计算版")
    public R shopBusinessDaysTimes(@NotNull(message = "店铺id不能为空") @RequestParam("shopId") Long shopId ,
                                   @Pattern(regexp = "["+ BusinessTypeEnum.ALL +"]", message = "交付方式值错误！") String receivingMethod,
                                   @RequestParam(required = false) Long addressBookId) throws Exception {
        GeneratedPredetermineDayAndTimesInfo generatedPredetermineDayAndTimesInfo =  shopService.getShopBusinessDaysTimes(shopId,receivingMethod,addressBookId);
        return R.ok().data(generatedPredetermineDayAndTimesInfo);
    }

    @GetMapping("/shop-delivery-info-by-user-location")
    @ApiOperation("根据用户的经纬度信息获取与指定店铺的配送信息（用时）")
    @NoAuthentication
    public R shopDeliveryInfoByUserLocation(@NotNull(message = "店铺id不能为空") @RequestParam("shopId") Long shopId,
                                            @NotNull(message = "经度不能为空") @RequestParam("longitude") Double longitude,
                                            @NotNull(message = "纬度不能为空") @RequestParam("latitude") Double latitude) {
        ShopToUserDeliveryInfo shopToUserDeliveryInfo = shopService.getShopDeliveryInfoByUserGeoCoordinates(shopId,new GeoCoordinates(longitude,latitude));
        return R.ok().data(shopToUserDeliveryInfo);
    }

    @GetMapping("/create-order-basic-info")
    @ApiOperation("订单额外费用")
    @NoAuthentication
    public R getCreateOrderBasicInfo(@RequestParam("shopId") Long shopId) {
        CreateOrderShopBasicInfo shopAdditionalCosts = shopService.getCreateOrderBasicInfo(shopId);
        return R.ok().data(shopAdditionalCosts);
    }

    @GetMapping("/phone")
    @ApiOperation("获取店家联系电话")
    @NoAuthentication
    public R getShopPhone(@NotNull(message = "商家id不能为空！") @RequestParam("shopId") Long shopId) {
        return R.ok().data(shopService.getShopPhone(shopId));
    }

    @GetMapping("/list-shop-info-for-order")
    @ApiOperation("后端内部模块接口-为订单获取店铺信息")
    @PublicAPI(modules = {ModuleSecurityNames.ORDER,ModuleSecurityNames.USER})
    @OnlySystemCall
    public R getShopInfoListForOrder(@NotBlank(message = "要查询的店铺信息不能为空") @RequestParam("shopIds") String shopIds) {
        return R.ok().data(shopService.getShopInfoListForOrder(Arrays.stream(shopIds.split(",")).collect(Collectors.toList())));
    }


    @GetMapping("/address")
    @ApiOperation("获取店铺地址")
    @NoAuthentication
    public R getShopDeliveryInfo(@NotNull(message = "商家id不能为空！") @RequestParam("shopId") Long shopId) {
        return R.require(ShopForRider.class, shopService.getShopAddress(shopId));
    }

    @GetMapping("/shop-basic-info")
    @ApiOperation("获取店铺基本信息-回显/显示")
    public R getShopBasicInfo() {
        return R.require(ShopBasicInfo.class,shopService.getShopBasicInfo());
    }

    @PutMapping("/shop-basic-info")
    @ApiOperation("修改店铺基本信息")
    @RequiresRoles(value = {ShopRole.admin})
    public R updateShopBasicInfo(@Valid @RequestBody ShopBasicInfo shopBasicInfo) {
        return R.capture(()->shopService.updateShopBasicInfo(shopBasicInfo));
    }

    @GetMapping("/business-config")
    @ApiOperation("获取店铺经营信息")
    public R queryBusinessConfig() {
        return R.require(ShopBusinessConfigVO.class,shopService.queryBusinessConfig());
    }

    @PutMapping("/business-config")
    @ApiOperation("修改店铺经营信息")
    @RequiresRoles(value = {ShopRole.admin})
    public R updateBusinessConfig(@RequestBody @Valid @GeoConvert ShopBusinessConfig shopBusinessConfig) {
        return R.capture(()->shopService.updateBusinessConfig(shopBusinessConfig));
    }

    /**
     * 店铺可用券-请求
     * @param shopId
     * @return
     * @throws Exception
     */
    @GetMapping("/applicable-shop-preferential/{shopId}")
    @ApiOperation("查询可用于店铺优惠的优惠信息（活动与券）")
    @NoAuthentication
    public R queryApplicableShopPreferential(@PathVariable("shopId") Long shopId) throws Exception {
        return R.require(ShopPreferentialLabelInfoVO.class,shopService.queryPreferentialInfoByShopId(shopId));
    }

    @GetMapping("/query-shop-display-info")
    @ApiOperation("根据店铺ids查询店铺信息列表")
    @NoAuthentication
    public R queryShopsDisplayInfo(@RequestParam("shopIds") List<Long> shopIds) {
        return R.require(shopService.queryShopsDisplayInfo(shopIds));
    }

    @GetMapping("/delivery-method/{shopId}")
    @ApiOperation("查询店铺的使用配送方式")
    @NoAuthentication
    public R queryShopDeliveryMethod(@PathVariable("shopId") Long shopId) {
        return R.require(Short.class, shopService.queryShopDeliveryMethod(shopId));
    }

    @GetMapping("/select-shop-info-for-user-order-map/{shopId}")
    @ApiOperation("获取店铺信息-用于用户查看外卖信息的地图展示")
    @NoAuthentication
    public R selectShopInfoForUserOrderMap(@PathVariable("shopId") Long shopId) {
        return R.require(ShopForUserOrderMapVO.class, shopService.selectShopInfoForUserOrderMap(shopId));
    }

    @ApiOperation("查出用户关注的店铺-关注时间降序")
    @GetMapping("/allFollow")
    @PublicAPI(modules = {ModuleSecurityNames.USER})
    public R allFollow(@ModelAttribute FollowShopPageDTO pageDTO) {
        return R.require(PageVO.parse(shopService.followListPage(pageDTO)));
    }








}

